#include "dataformatwizard.h"
#include "binaryfile.h"
#include "textfile.h"
#include "unknownfile.h"
#include "auxclasses.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFormLayout>
#include <QScrollArea>
#include <QTreeView>
#include <QLabel>
#include <QPushButton>
#include <QCheckBox>
#include <QGroupBox>
#include <QSpinBox>
#include <QComboBox>
#include <QStandardItemModel>
#include <QStandardItem>
#include <QModelIndex>

DataFormatWizard::DataFormatWizard(QList<BinaryFile *> *binaryFileList, QList<FileGroup *> *binaryFileGroupList,
                                   QStandardItemModel *binaryFileGroupModel, int numNewBinaryFiles,
                                   QList<TextFile *> *textFileList, QList<FileGroup *> *textFileGroupList,
                                   QStandardItemModel *textFileGroupModel, int numNewTextFiles,
                                   QList<UnknownFile *> *unknownFileList, QList<FileGroup *> *unknownFileGroupList,
                                   QStandardItemModel *unknownFileGroupModel, int numUnknownFiles,
                                   QWidget *parent) : QWizard(parent)
{
    setWindowTitle(tr("Data format wizard"));
    addPage(new IntroPage(this));
    if (numNewBinaryFiles != 0) {
        BinaryFileGroupPage *binaryFileGroupPage
                = new BinaryFileGroupPage(binaryFileList, binaryFileGroupList, binaryFileGroupModel, numNewBinaryFiles, this);
        BinaryDataFormatPage *binaryDataFormatPage
                = new BinaryDataFormatPage(binaryFileList, binaryFileGroupList, this);
        connect(binaryFileGroupPage, SIGNAL(newGroupAdded()), binaryDataFormatPage, SLOT(newGroupAdded()));
        addPage(binaryFileGroupPage);
        addPage(binaryDataFormatPage);
    }
}

IntroPage::IntroPage(QWidget *parent) : QWizardPage(parent)
{
    setTitle(tr("Data storing format specification"));
    QLabel *label_intro = new QLabel(tr("The files you inputted contain non-uniform data "
                                        "format, please go through the following steps to"
                                        " provide enough information for reading in them."));
    label_intro->setWordWrap(true);
    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(label_intro);
    setLayout(layout);
}

BinaryFileGroupPage::BinaryFileGroupPage(QList<BinaryFile *> *binaryFileListIn, QList<FileGroup *> *binaryFileGroupListIn,
                                         QStandardItemModel *binaryFileGroupModelIn, int numNewBinaryFilesIn, QWidget *parent) : QWizardPage(parent)
{
    binaryFileList = binaryFileListIn;
    binaryFileGroupList = binaryFileGroupListIn;
    binaryFileGroupModel = binaryFileGroupModelIn;
    numNewBinaryFiles = numNewBinaryFilesIn;

    setTitle(tr("Group binary files"));

    layout_page = new QVBoxLayout;

    // setup several buttons
    layout_buttons = new QHBoxLayout;
    button_select = new QPushButton(tr("Select All/None"));
    button_add = new QPushButton(tr("Add To Existed Group"));
    int numGroups = binaryFileGroupList->size();
    if (numGroups == 0) {
        button_add->setDisabled(true);
    }
    button_submit = new QPushButton(tr("Submit A Group"));
    layout_buttons->addWidget(button_select);
    layout_buttons->addWidget(button_add);
    connect(button_add, SIGNAL(clicked()), this, SLOT(addToGroup()));
    layout_buttons->addWidget(button_submit);
    connect(button_submit, SIGNAL(clicked()), this, SLOT(submitGroup()));

    // setup old grouped files tree view
    groupBox_oldFiles = new QGroupBox(tr("old grouped files"));
    layout_oldFileTree = new QVBoxLayout;
    treeView_oldFileTree = new QTreeView;
    layout_oldFileTree->addWidget(treeView_oldFileTree);
    groupBox_oldFiles->setLayout(layout_oldFileTree);
    treeView_oldFileTree->setModel(binaryFileGroupModel);

    // setup new ungrouped files list with check boxes
    groupBox_newFiles = new QGroupBox(tr("new ungrouped files"));
    layout_newFileList = new QVBoxLayout;
    checkBox_newFileList = new QList<QCheckBox *>;
    int numOldBinaryFiles = binaryFileList->size()-numNewBinaryFiles;
    for (int i = numOldBinaryFiles; i < binaryFileList->size(); ++i) {
        QString newFilePath = binaryFileList->at(i)->filePath;
        checkBox_newFileList->append(new QCheckBox(newFilePath));
        int j = i-numOldBinaryFiles;
        layout_newFileList->addWidget(checkBox_newFileList->at(j));
        connect(button_select, SIGNAL(clicked()), checkBox_newFileList->at(j), SLOT(toggle()));
    }
    groupBox_newFiles->setLayout(layout_newFileList);

    // setup message area
    groupBox_message = new QGroupBox(tr("message"));
    layout_message = new QVBoxLayout;
    groupBox_message->setLayout(layout_message);
    label_message = new QLabel;
    layout_message->addWidget(label_message);

    // setup layout for page
    layout_page->addWidget(groupBox_oldFiles);
    layout_page->addWidget(groupBox_newFiles);
    layout_page->addWidget(groupBox_message);
    layout_page->addLayout(layout_buttons);

    label_message->setText(tr("Submit a group, or add files to existed group"));
    isAllFilesInGroups = false;

    setLayout(layout_page);
}

void BinaryFileGroupPage::submitGroup()
{
    bool isValid = false;
    bool isFinished = true;
    int numGroups = binaryFileGroupList->size();
    binaryFileGroupList->append(new FileGroup);
    binaryFileGroupModel->appendRow(new QStandardItem(QString(tr("Group %1").arg(numGroups))));
    for (int i = 0; i < numNewBinaryFiles; ++i) {
        if (checkBox_newFileList->at(i)->isEnabled() == true) {
            if (checkBox_newFileList->at(i)->isChecked() == true) {
                isValid = true;
                int j = binaryFileList->size()-numNewBinaryFiles+i;
                binaryFileGroupList->last()->memberIndex->append(j);
                QStandardItem *newAddedFile = new QStandardItem(binaryFileList->at(j)->fileName);
                binaryFileGroupModel->item(numGroups, 0)->appendRow(newAddedFile);
                checkBox_newFileList->at(i)->setVisible(false);
                checkBox_newFileList->at(i)->setDisabled(true);
            } else {
                isFinished = false;
            }
        }
    }
    if (isValid == false) {
        // no file selected, invalid operation
        binaryFileGroupList->removeLast();
        binaryFileGroupModel->removeRow(numGroups);
        return;
    } else {
        emit newGroupAdded();
    }
    if (isFinished == true) {
        label_message->setText(tr("Files have been grouped, click next."));
        button_submit->setDisabled(true);
        button_select->setDisabled(true);
        isAllFilesInGroups = true;
        emit completeChanged();
    }
}

void BinaryFileGroupPage::addToGroup()
{
    QDialog *dialog = new QDialog;
    dialog->setModal(true);
    QVBoxLayout *layout_dialog = new QVBoxLayout;
    dialog->setLayout(layout_dialog);
    QComboBox *comboBox_existedGroups = new QComboBox;
    layout_dialog->addWidget(comboBox_existedGroups);
    int numGroups = binaryFileGroupList->size();
    for (int i = 0; i < numGroups; ++i) {
        QString groupName = binaryFileGroupModel->item(i, 0)->data(Qt::DisplayRole).toString();
        comboBox_existedGroups->addItem(groupName);
    }
    QPushButton *button_OK = new QPushButton(tr("OK"));
    QPushButton *button_cancel = new QPushButton(tr("Cancel"));
    QHBoxLayout *layout_buttons = new QHBoxLayout;
    layout_buttons->addWidget(button_OK);
    layout_buttons->addWidget(button_cancel);
    layout_dialog->addLayout(layout_buttons);
    connect(button_OK, SIGNAL(clicked()), dialog, SLOT(accept()));
    connect(button_cancel, SIGNAL(clicked()), dialog, SLOT(reject()));
    dialog->exec();
    if (dialog->result() == QDialog::Accepted) {
        bool isFinished = true;
        int k = comboBox_existedGroups->currentIndex();
        for (int i = 0; i < numNewBinaryFiles; ++i) {
            if (checkBox_newFileList->at(i)->isEnabled() == true) {
                if (checkBox_newFileList->at(i)->isChecked() == true) {
                    int j = binaryFileList->size()-i-1;
                    binaryFileGroupList->last()->memberIndex->append(j);
                    QStandardItem *newAddedFile = new QStandardItem(binaryFileList->at(j)->fileName);
                    binaryFileGroupModel->item(k, 0)->appendRow(newAddedFile);
                    checkBox_newFileList->at(i)->setVisible(false);
                    checkBox_newFileList->at(i)->setDisabled(true);
                    // inherit data format information from other group menbers
                    int l = binaryFileGroupList->at(k)->memberIndex->at(0);
                    binaryFileList->at(j)->numDatas = binaryFileList->at(l)->numDatas;
                    for (int m = 0; m < binaryFileList->at(l)->numDatas; ++m) {
                        binaryFileList->at(j)->dataNameList.append(binaryFileList->at(l)->dataNameList.at(m));
                    }
                    binaryFileList->at(j)->numSpatialDimensions = binaryFileList->at(l)->numSpatialDimensions;
                    binaryFileList->at(j)->numTemporalLayers = binaryFileList->at(l)->numTemporalLayers;
                    binaryFileList->at(j)->isRegular = binaryFileList->at(l)->isRegular;
                    binaryFileList->at(j)->numSpatialPoints = binaryFileList->at(l)->numSpatialPoints;
                    binaryFileList->at(j)->numSpatialPointsAlongAxis1 = binaryFileList->at(l)->numSpatialPointsAlongAxis1;
                    binaryFileList->at(j)->numSpatialPointsAlongAxis2 = binaryFileList->at(l)->numSpatialPointsAlongAxis2;
                    binaryFileList->at(j)->numSpatialPointsAlongAxis3 = binaryFileList->at(l)->numSpatialPointsAlongAxis3;
                } else {
                    isFinished = false;
                }
            }
        }
        if (isFinished == true) {
            label_message->setText(tr("Files have been grouped, click next."));
            button_submit->setDisabled(true);
            button_select->setDisabled(true);
            isAllFilesInGroups = true;
            emit completeChanged();
        }
    }
}

bool BinaryFileGroupPage::isComplete() const
{
    if (isAllFilesInGroups == false) {
        return false;
    } else {
        return true;
    }
}

BinaryDataFormatPage::BinaryDataFormatPage(QList<BinaryFile *> *binaryFileListIn,
                                           QList<FileGroup *> *binaryFileGroupListIn,
                                           QWidget *parent) : QWizardPage(parent)
{
    binaryFileList = binaryFileListIn;
    binaryFileGroupList = binaryFileGroupListIn;

    binaryDataFormatUI = new QList<BinaryDataFormatUI *>;

    setTitle(tr("Specify data format for each group"));

    layout_page = new QVBoxLayout;

    layout_buttons = new QHBoxLayout;
    button_previous = new QPushButton(tr("Previous Group"));
    layout_buttons->addWidget(button_previous);
    connect(button_previous, SIGNAL(clicked()), this, SLOT(goToPreviousGroup()));
    button_next = new QPushButton(tr("Next Group"));
    layout_buttons->addWidget(button_next);
    connect(button_next, SIGNAL(clicked()), this, SLOT(goToNextGroup()));
    button_submit = new QPushButton(tr("Submit"));
    layout_buttons->addWidget(button_submit);
    connect(button_submit, SIGNAL(clicked()), this, SLOT(submitDataFormat()));

    groupBoxList_dataFormat = new QList<QGroupBox *>;

    setLayout(layout_page);

    numNewGroups = 0;
    status = 0; // new
    isAllGroupsSet = false;
}

void BinaryDataFormatPage::initializePage()
{
    switch (status) {
    case (0) :
        int numGroups = binaryFileGroupList->size();
        for (int i = 0; i < numGroups; ++i) {
            QString groupName = QString(tr("Group %1")).arg(i);
            groupBoxList_dataFormat->append(new QGroupBox(groupName));
            if (i != 0) {
                groupBoxList_dataFormat->at(i)->setVisible(false);
            }
            binaryDataFormatUI->append(new BinaryDataFormatUI);
            groupBoxList_dataFormat->at(i)->setLayout(binaryDataFormatUI->at(i)->layout);
            if (binaryFileGroupList->at(i)->isNewGroup == false) {
                BinaryFile *file = binaryFileList->at(binaryFileGroupList->at(i)->memberIndex->at(0));
                binaryDataFormatUI->at(i)->setFrom(*file);
            }
        }
        currentGroupIndex = 0;
        layout_page->addWidget(groupBoxList_dataFormat->at(0));
        layout_page->addLayout(layout_buttons);

        status = 1; // created
        break;
    case (1) :
        break;
    }
}

void BinaryDataFormatPage::newGroupAdded()
{
    numNewGroups++;
}

void BinaryDataFormatPage::submitDataFormat()
{
    // set the binary file group's data format information
    int numFiles = binaryFileGroupList->at(currentGroupIndex)->memberIndex->size();
    for (int i = 0; i < numFiles; ++i) {
        int j = binaryFileGroupList->at(currentGroupIndex)->memberIndex->at(i);
        binaryDataFormatUI->at(currentGroupIndex)->setTo(binaryFileList->at(j));
    }
    binaryFileGroupList->at(currentGroupIndex)->isNewGroup = false;

    // judge whether all the group has been set
    int numGroups = binaryFileGroupList->size();
    bool isFinished = true;
    for (int i = 0; i < numGroups; ++i)
        if (binaryFileGroupList->at(i)->isNewGroup == true)
            isFinished = false;
    if (isFinished == true) {
        isAllGroupsSet = true;
        emit completeChanged();
    }

    // judge the program flow
    if (currentGroupIndex == numGroups-1) {
        button_submit->setDisabled(true);
        return;
    } else {
        currentGroupIndex++;
        groupBoxList_dataFormat->at(currentGroupIndex-1)->setVisible(false);
        layout_page->removeWidget(groupBoxList_dataFormat->at(currentGroupIndex-1));
        groupBoxList_dataFormat->at(currentGroupIndex)->setVisible(true);
        layout_page->insertWidget(0, groupBoxList_dataFormat->at(currentGroupIndex));
    }
}

void BinaryDataFormatPage::goToPreviousGroup()
{
    if (currentGroupIndex == 0) {
        return;
    } else {
        currentGroupIndex--;
        groupBoxList_dataFormat->at(currentGroupIndex+1)->setVisible(false);
        layout_page->removeWidget(groupBoxList_dataFormat->at(currentGroupIndex+1));
        groupBoxList_dataFormat->at(currentGroupIndex)->setVisible(true);
        layout_page->insertWidget(0, groupBoxList_dataFormat->at(currentGroupIndex));
    }
}

void BinaryDataFormatPage::goToNextGroup()
{
    if (currentGroupIndex == binaryFileGroupList->size()-1) {
        return;
    } else {
        currentGroupIndex++;
        groupBoxList_dataFormat->at(currentGroupIndex-1)->setVisible(false);
        layout_page->removeWidget(groupBoxList_dataFormat->at(currentGroupIndex-1));
        groupBoxList_dataFormat->at(currentGroupIndex)->setVisible(true);
        layout_page->insertWidget(0, groupBoxList_dataFormat->at(currentGroupIndex));
    }
}

bool BinaryDataFormatPage::isComplete() const
{
    if (isAllGroupsSet == true) {
        return true;
    } else {
        return false;
    }
}
